package com.wupaas.boot.core.business.oplog;

import com.wupaas.boot.core.business.context.ServletContextHolder;
import com.wupaas.boot.core.business.context.SpringContextHolder;
import com.wupaas.boot.core.business.oplog.format.IOplogFormat;
import com.wupaas.boot.core.business.security.jwt.JwtUtil;
import com.wupaas.boot.core.common.util.IpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @author JueYue
 * @date 2021-08-21-8-4
 * @since 1.0
 */
@Component
@Aspect
public class OpLogAspect {

    @Autowired
    private OplogService oplogService;

    @Resource(name = "baseOplogFormatService")
    private IOplogFormat formatService;

    @Pointcut(value = "@annotation(com.wupaas.boot.core.business.oplog.OpLog)")
    public void opLog() {

    }

    @Around(value = "opLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = ServletContextHolder.getRequest();
        OpLogModel log = new OpLogModel();
        log.setIp(getIp(request));
        log.setUserId(JwtUtil.getUserName());
        OpLog opLog = getAnnotation(point);
        log.setCreateTime(new Date());
        log.setType(opLog.type().name());
        log.setUrl(request.getPathInfo());
        String packages = point.getThis().getClass().getName();
        if (packages.indexOf("$$EnhancerBySpringCGLIB$$") > -1) {
            try {
                // 去掉CGLIB动态生成的类
                packages = packages.substring(0, packages.indexOf("$$"));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        log.setMethod(packages + "." + point.getTarget().getClass().getName() + "." + point.getSignature().getName());
        log.setMessage(getMessage(opLog.action(),opLog.actionFormat(),point.getArgs()));
        Object object;
        long starTime = System.nanoTime();
        try {
            object = point.proceed();
        } catch (Exception e) {
            log.setTakeTime(System.nanoTime() - starTime);
            log.setSucceed("2");
            oplogService.save(log);
            throw e;
        }
        log.setTakeTime(System.nanoTime() - starTime);
        log.setSucceed("1");
        oplogService.save(log);
        return object;
    }

    /**
     * 获取具体操作信息
     * @param action
     * @param actionFormat
     * @param args
     * @return
     */
    private String getMessage(String action, String actionFormat, Object[] args) {
        IOplogFormat format = null;
        if (actionFormat.equals("baseOplogFormatService")){
            format= formatService;
        } else {
            format = SpringContextHolder.getBean(actionFormat);
        }
        return format.format(action,args);
    }

    private String getIp(HttpServletRequest request) {
        String ip = IpUtil.getIpAddr(request);
        ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
        return ip;
    }

    /**
     * 获取自定义注解描述
     * @param joinPoint
     * @return
     * @throws Exception
     */
    public static OpLog getAnnotation(ProceedingJoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        OpLog opLog = null;
        for (Method m : method) {
            if (m.getName().equals(methodName)) {
                Class[] tmpCs = m.getParameterTypes();
                if (tmpCs.length == arguments.length) {
                    opLog = m.getAnnotation(OpLog.class);
                    if (opLog != null) {
                    }
                    break;
                }
            }
        }
        return opLog;
    }

}
